home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, John F. Haugh II
- * All rights reserved.
- *
- * Permission is granted to copy and create derivative works for any
- * non-commercial purpose, provided this copyright notice is preserved
- * in all copies of source code, or included in human readable form
- * and conspicuously displayed on all copies of object code or
- * distribution media.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)useradd.c 3.8 19:40:07 12/28/91";
- #endif
-
- #include "config.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <errno.h>
- #include "pwd.h"
- #include <grp.h>
- #include <ctype.h>
- #include <fcntl.h>
- #include <time.h>
-
- #ifdef BSD
- #include <strings.h>
- #else
- #include <string.h>
- #endif
-
- #include "shadow.h"
-
- #ifdef USE_SYSLOG
- #include <syslog.h>
-
- #ifndef LOG_WARN
- #define LOG_WARN LOG_WARNING
- #endif
- #endif
-
- gid_t def_group;
- char def_home[BUFSIZ];
- char def_shell[BUFSIZ];
- char def_template[BUFSIZ] = "/etc/skel";
- long def_inactive;
- long def_expire;
- char def_file[] = "/etc/default/useradd";
-
- #ifndef NGROUPS_MAX
- #define NGROUPS_MAX 64
- #endif
-
- #define VALID(s) (strcspn (s, ":\n") == strlen (s))
-
- char user_name[BUFSIZ];
- uid_t user_id;
- gid_t user_gid;
- char user_comment[BUFSIZ];
- char user_home[BUFSIZ];
- char user_shell[BUFSIZ];
- long user_expire;
- int user_ngroups;
- gid_t user_groups[NGROUPS_MAX];
-
- char *Prog;
-
- int uflg; /* specify user ID for new account */
- int oflg; /* permit non-unique user ID to be specified with -u */
- int gflg; /* primary group ID for new account */
- int Gflg; /* secondary group set for new account */
- int dflg; /* home directory for new account */
- int bflg; /* new default root of home directory */
- int sflg; /* shell program for new account */
- int cflg; /* comment (GECOS) field for new account */
- int mflg; /* create user's home directory if it doesn't exist */
- int kflg; /* specify a directory to fill new user directory */
- int fflg; /* days until account with expired password is locked */
- int eflg; /* days after password changed before it becomes expired */
- int Dflg; /* set/show new user default values */
-
- #ifdef NDBM
- extern int pw_dbm_mode;
- extern int sp_dbm_mode;
- extern int gr_dbm_mode;
- #ifdef SHADOWGRP
- extern int sg_dbm_mode;
- #endif
- #endif
- extern FILE *fopen();
- extern int fclose();
- extern char *malloc();
- extern char *mktemp();
-
- extern struct group *getgrnam();
- extern struct group *getgrgid();
- extern struct group *gr_next();
- extern struct group *gr_locate();
- extern int gr_lock();
- extern int gr_unlock();
- extern int gr_rewind();
- extern int gr_open();
-
- #ifdef SHADOWGRP
- extern struct sgrp *sgr_next();
- extern int sgr_lock();
- extern int sgr_unlock();
- extern int sgr_rewind();
- extern int sgr_open();
- #endif
-
- extern struct passwd *getpwnam();
- extern struct passwd *pw_next();
- extern int pw_lock();
- extern int pw_unlock();
- extern int pw_rewind();
- extern int pw_open();
-
- extern int spw_lock();
- extern int spw_unlock();
- extern int spw_open();
-
- #define DAY (24L*3600L)
- #define WEEK (7*DAY)
-
- #ifdef ITI_AGING
- #define SCALE (1)
- #else
- #define SCALE (DAY)
- #endif
-
- /*
- * days and juldays are used to compute the number of days in the
- * current month, and the cummulative number of days in the preceding
- * months. they are declared so that january is 1, not 0.
- */
-
- static short days[13] = { 0,
- 31, 28, 31, 30, 31, 30, /* JAN - JUN */
- 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */
-
- static short juldays[13] = { 0,
- 0, 31, 59, 90, 120, 151, /* JAN - JUN */
- 181, 212, 243, 273, 304, 334 }; /* JUL - DEC */
-
- #ifdef NEED_RENAME
- /*
- * rename - rename a file to another name
- *
- * rename is provided for systems which do not include the rename()
- * system call.
- */
-
- int
- rename (begin, end)
- char *begin;
- char *end;
- {
- struct stat s1, s2;
- extern int errno;
- int orig_err = errno;
-
- if (stat (begin, &s1))
- return -1;
-
- if (stat (end, &s2)) {
- errno = orig_err;
- } else {
-
- /*
- * See if this is a cross-device link. We do this to
- * insure that the link below has a chance of working.
- */
-
- if (s1.st_dev != s2.st_dev) {
- errno = EXDEV;
- return -1;
- }
-
- /*
- * See if we can unlink the existing destination
- * file. If the unlink works the directory is writable,
- * so there is no need here to figure that out.
- */
-
- if (unlink (end))
- return -1;
- }
-
- /*
- * Now just link the original name to the final name. If there
- * was no file previously, this link will fail if the target
- * directory isn't writable. The unlink will fail if the source
- * directory isn't writable, but life stinks ...
- */
-
- if (link (begin, end) || unlink (begin))
- return -1;
-
- return 0;
- }
- #endif
-
- /*
- * strtoday - compute the number of days since 1970.
- *
- * the total number of days prior to the current date is
- * computed. january 1, 1970 is used as the origin with
- * it having a day number of 0.
- */
-
- long
- strtoday (str)
- char *str;
- {
- char slop[2];
- int month;
- int day;
- int year;
- long total;
-
- /*
- * start by separating the month, day and year. this is
- * a chauvanistic program - it only takes date input in
- * the standard USA format.
- */
-
- if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
- return -1;
-
- /*
- * the month, day of the month, and year are checked for
- * correctness and the year adjusted so it falls between
- * 1970 and 2069.
- */
-
- if (month < 1 || month > 12)
- return -1;
-
- if (day < 1)
- return -1;
-
- if ((month != 2 || (year % 4) != 0) && day > days[month])
- return -1;
- else if ((month == 2 && (year % 4) == 0) && day > 29)
- return -1;
-
- if (year < 0)
- return -1;
- else if (year < 69)
- year += 2000;
- else if (year < 99)
- year += 1900;
-
- if (year < 1970 || year > 2069)
- return -1;
-
- /*
- * the total number of days is the total number of days in all
- * the whole years, plus the number of leap days, plus the
- * number of days in the whole months preceding, plus the number
- * of days so far in the month.
- */
-
- total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
- total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
- total += (long) day - 1;
-
- return total;
- }
-
- /*
- * add_list - add a member to a list of group members
- *
- * the array of member names is searched for the new member
- * name, and if not present it is added to a freshly allocated
- * list of users.
- */
-
- char **
- add_list (list, member)
- char **list;
- char *member;
- {
- int i;
- char **tmp;
-
- /*
- * Scan the list for the new name. Return the original list
- * pointer if it is present.
- */
-
- for (i = 0;list[i] != (char *) 0;i++)
- if (strcmp (list[i], member) == 0)
- return list;
-
- /*
- * Allocate a new list pointer large enough to hold all the
- * old entries, and the new entries as well.
- */
-
- if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
- return 0;
-
- /*
- * Copy the original list to the new list, then append the
- * new member and NULL terminate the result. This new list
- * is returned to the invoker.
- */
-
- for (i = 0;list[i] != (char *) 0;i++)
- tmp[i] = list[i];
-
- tmp[i++] = strdup (member);
- tmp[i] = (char *) 0;
-
- return tmp;
- }
-
- /*
- * get_defaults - read the defaults file
- *
- * get_defaults() reads the defaults file for this command. It sets
- * the various values from the file, or uses built-in default values
- * if the file does not exist.
- */
-
- void
- get_defaults ()
- {
- FILE *fp;
- char buf[BUFSIZ];
- char *cp;
- struct group *grp;
-
- /*
- * Open the defaults file for reading.
- */
-
- if (! (fp = fopen (def_file, "r"))) {
-
- /*
- * No defaults file - set up the defaults that are given
- * in the documentation.
- */
-
- def_group = 1;
- strcpy (def_home, "/home");
- def_inactive = 0;
- def_expire = 0;
- return;
- }
-
- /*
- * Read the file a line at a time. Only the lines that have
- * relevant values are used, everything else can be ignored.
- */
-
- while (fgets (buf, BUFSIZ, fp)) {
- if (cp = strrchr (buf, '\n'))
- *cp = '\0';
-
- /*
- * Primary GROUP identifier
- */
-
- if (strncmp ("GROUP=", buf, 6) == 0) {
- cp = buf + 6;
- if (isdigit (*cp))
- def_group = atoi (cp);
- else if (grp = getgrnam (cp))
- def_group = grp->gr_gid;
- else
- fprintf (stderr, "%s: unknown group %s\n",
- Prog, cp);
- }
-
- /*
- * Default HOME filesystem
- */
-
- else if (strncmp ("HOME=", buf, 5) == 0) {
- strncpy (def_home, buf + 5, BUFSIZ);
- }
-
- /*
- * Default Login Shell command
- */
-
- else if (strncmp ("SHELL=", buf, 6) == 0) {
- strncpy (def_shell, buf + 6, BUFSIZ);
- }
-
- /*
- * Default Password Inactive value
- */
-
- else if (strncmp ("INACTIVE=", buf, 9) == 0) {
- def_inactive = atoi (buf + 9);
- }
-
- /*
- * Default Password Expiration value
- */
-
- else if (strncmp ("EXPIRE=", buf, 7) == 0) {
- def_expire = atoi (buf + 7);
- }
- }
- }
-
- /*
- * show_defaults - show the contents of the defaults file
- *
- * show_defaults() displays the values that are used from the default
- * file and the built-in values.
- */
-
- void
- show_defaults ()
- {
- printf ("GROUP=%d\n", def_group);
- printf ("HOME=%s\n", def_home);
- printf ("INACTIVE=%d\n", def_inactive);
- printf ("EXPIRE=%d\n", def_expire);
- }
-
- /*
- * set_defaults - write new defaults file
- *
- * set_defaults() re-writes the defaults file using the values that
- * are currently set. Duplicated lines are pruned, missing lines are
- * added, and unrecognized lines are copied as is.
- */
-
- int
- set_defaults ()
- {
- FILE *ifp;
- FILE *ofp;
- char buf[BUFSIZ];
- static char new_file[] = "/etc/default/nuaddXXXXXX";
- char *cp;
- int out_group = 0;
- int out_home = 0;
- int out_inactive = 0;
- int out_expire = 0;
-
- /*
- * Create a temporary file to copy the new output to.
- */
-
- mktemp (new_file);
- if (! (ofp = fopen (new_file, "w"))) {
- fprintf (stderr, "%s: cannot create new defaults file\n", Prog);
- return -1;
- }
-
- /*
- * Open the existing defaults file and copy the lines to the
- * temporary files, using any new values. Each line is checked
- * to insure that it is not output more than once.
- */
-
- if (ifp = fopen (def_file, "r")) {
- while (fgets (buf, BUFSIZ, ifp)) {
- if (cp = strrchr (buf, '\n'))
- *cp = '\0';
-
- if (strncmp ("GROUP=", buf, 6) == 0) {
- if (! out_group)
- fprintf (ofp, "GROUP=%d\n", def_group);
-
- out_group++;
- } else if (strncmp ("HOME=", buf, 5) == 0) {
- if (! out_home)
- fprintf (ofp, "HOME=%s\n", def_home);
-
- out_home++;
- } else if (strncmp ("INACTIVE=", buf, 9) == 0) {
- if (! out_inactive)
- fprintf (ofp, "INACTIVE=%d\n",
- def_inactive);
-
- out_inactive++;
- } else if (strncmp ("EXPIRE=", buf, 7) == 0) {
- if (! out_expire)
- fprintf (ofp, "EXPIRE=%d\n",
- def_expire);
-
- out_expire++;
- } else
- fprintf (ofp, "%s\n", buf);
- }
- fclose ((FILE *) ifp);
- }
-
- /*
- * Check each line to insure that every line was output. This
- * causes new values to be added to a file which did not previously
- * have an entry for that value.
- */
-
- if (! out_group)
- fprintf (ofp, "GROUP=%d\n", def_group);
-
- if (! out_home)
- fprintf (ofp, "HOME=%s\n", def_home);
-
- if (! out_inactive)
- fprintf (ofp, "INACTIVE=%d\n", def_inactive);
-
- if (! out_expire)
- fprintf (ofp, "EXPIRE=%d\n", def_expire);
-
- /*
- * Flush and close the file. Check for errors to make certain
- * the new file is intact.
- */
-
- (void) fflush (ofp);
- if (ferror (ofp) || fclose ((FILE *) ofp)) {
- unlink (new_file);
- return -1;
- }
-
- /*
- * Rename the current default file to its backup name.
- */
-
- sprintf (buf, "%s-", def_file);
- if (rename (def_file, buf) && errno != ENOENT) {
- sprintf (buf, "%s: rename: %s", Prog, def_file);
- perror (buf);
- unlink (new_file);
- return -1;
- }
-
- /*
- * Rename the new default file to its correct name.
- */
-
- if (rename (new_file, def_file)) {
- sprintf (buf, "%s: rename: %s", Prog, new_file);
- perror (buf);
- return -1;
- }
- #ifdef USE_SYSLOG
- syslog (LOG_INFO,
- "defaults: group=%d, home=%s, inactive=%d, expire=%d\n",
- def_group, def_home, def_inactive, def_expire);
- #endif
- return 0;
- }
-
- /*
- * get_groups - convert a list of group names to an array of group IDs
- *
- * get_groups() takes a comma-separated list of group names and
- * converts it to an array of group ID values. Any unknown group
- * names are reported as errors.
- */
-
- int
- get_groups (list)
- char *list;
- {
- char *cp;
- struct group *grp;
- int errors = 0;
-
- /*
- * Initialize the list to be empty
- */
-
- user_ngroups = 0;
-
- if (! *list)
- return 0;
-
- /*
- * So long as there is some data to be converted, strip off
- * each name and look it up. A mix of numerical and string
- * values for group identifiers is permitted.
- */
-
- do {
- /*
- * Strip off a single name from the list
- */
-
- if (cp = strchr (list, ','))
- *cp++ = '\0';
-
- /*
- * Names starting with digits are treated as numerical
- * GID values, otherwise the string is looked up as is.
- */
-
- if (isdigit (*list))
- grp = getgrgid (atoi (list));
- else
- grp = getgrnam (list);
-
- /*
- * There must be a match, either by GID value or by
- * string name.
- */
-
- if (! grp) {
- fprintf (stderr, "%s: unknown group %s\n", Prog, list);
- errors++;
- }
-
- /*
- * Add the GID value from the group file to the user's
- * list of groups.
- */
-
- user_groups[user_ngroups++] = grp->gr_gid;
-
- list = cp;
- } while (list);
-
- /*
- * Any errors in finding group names are fatal
- */
-
- if (errors)
- return -1;
-
- return 0;
- }
-
- /*
- * usage - display usage message and exit
- */
-
- usage ()
- {
- fprintf (stderr,
- "usage:\t%s [-u uid [-o]] [-g group] [-G group,...] \n", Prog);
- fprintf (stderr,
- "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n");
- fprintf (stderr,
- "\t\t[-f inactive] [-e expire] name\n");
-
- fprintf (stderr,
- "\t%s -D [-g group] [-b base] [-f inactive] [-e expire]\n",
- Prog);
-
- exit (1);
- }
-
- /*
- * new_pwent - initialize the values in a password file entry
- *
- * new_pwent() takes all of the values that have been entered and
- * fills in a (struct passwd) with them.
- */
-
- void
- new_pwent (pwent)
- struct passwd *pwent;
- {
- memset (pwent, 0, sizeof *pwent);
- pwent->pw_name = user_name;
- pwent->pw_passwd = "*";
- pwent->pw_age = "";
- pwent->pw_uid = user_id;
- pwent->pw_gid = user_gid;
- pwent->pw_gecos = user_comment;
- pwent->pw_comment = "";
- pwent->pw_dir = user_home;
- pwent->pw_shell = user_shell;
- }
-
- /*
- * new_spent - initialize the values in a shadow password file entry
- *
- * new_spent() takes all of the values that have been entered and
- * fills in a (struct spwd) with them.
- */
-
- void
- new_spent (spent)
- struct spwd *spent;
- {
- memset (spent, 0, sizeof *spent);
- spent->sp_namp = user_name;
- spent->sp_pwdp = "!";
- spent->sp_lstchg = 0;
- spent->sp_min = 0;
- spent->sp_max = def_expire;
- spent->sp_warn = 0;
- spent->sp_inact = def_inactive;
- spent->sp_expire = user_expire;
- }
-
- /*
- * grp_update - add user to secondary group set
- *
- * grp_update() takes the secondary group set given in user_groups
- * and adds the user to each group given by that set.
- */
-
- void
- grp_update ()
- {
- int i;
- struct group *grp;
- #ifdef SHADOWGRP
- struct sgrp *sgrp;
- #endif
-
- /*
- * Lock and open the group file. This will load all of the group
- * entries.
- */
-
- if (! gr_lock ()) {
- fprintf (stderr, "%s: error locking group file\n", Prog);
- exit (1);
- }
- if (! gr_open (O_RDWR)) {
- fprintf (stderr, "%s: error opening group file\n", Prog);
- exit (1);
- }
- #ifdef SHADOWGRP
- if (! sgr_lock ()) {
- fprintf (stderr, "%s: error locking shadow group file\n", Prog);
- exit (1);
- }
- if (! sgr_open (O_RDWR)) {
- fprintf (stderr, "%s: error opening shadow group file\n", Prog);
- exit (1);
- }
- #endif
-
- /*
- * Scan through the entire group file looking for the groups that
- * the user is a member of.
- */
-
- for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
-
- /*
- * See if the user specified this group as one of their
- * concurrent groups.
- */
-
- for (i = 0;i < user_ngroups;i++)
- if (grp->gr_gid == user_groups[i])
- break;
-
- if (i == user_ngroups)
- continue;
-
- /*
- * Add the username to the list of group members and
- * update the group entry to reflect the change.
- */
-
- grp->gr_mem = add_list (grp->gr_mem, user_name);
- if (! gr_update (grp)) {
- fprintf (stderr, "%s: error adding new group entry\n",
- Prog);
- exit (1);
- }
- #ifdef NDBM
- /*
- * Update the DBM group file with the new entry as well.
- */
-
- if (! gr_dbm_update (grp)) {
- fprintf (stderr, "%s: cannot add new dbm group entry\n",
- Prog);
- exit (1);
- }
- endgrent ();
- #endif
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "add `%s' to group `%s'\n",
- user_name, grp->gr_name);
- #endif
- }
-
- #ifdef SHADOWGRP
- /*
- * Scan through the entire shadow group file looking for the groups
- * that the user is a member of. The administrative list isn't
- * modified.
- */
-
- for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
-
- /*
- * See if the user specified this group as one of their
- * concurrent groups.
- */
-
- for (i = 0;i < user_ngroups;i++) {
- if (! (grp = gr_locate (sgrp->sg_name)))
- continue;
-
- if (grp->gr_gid == user_groups[i])
- break;
- }
- if (i == user_ngroups)
- continue;
-
- /*
- * Add the username to the list of group members and
- * update the group entry to reflect the change.
- */
-
- sgrp->sg_mem = add_list (sgrp->sg_mem, user_name);
- if (! sgr_update (sgrp)) {
- fprintf (stderr, "%s: error adding new group entry\n",
- Prog);
- exit (1);
- }
- #ifdef NDBM
- /*
- * Update the DBM group file with the new entry as well.
- */
-
- if (! sgr_dbm_update (sgrp)) {
- fprintf (stderr, "%s: cannot add new dbm group entry\n",
- Prog);
- exit (1);
- }
- endsgent ();
- #endif
- #ifdef USE_SYSLOG
- syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
- user_name, sgrp->sg_name);
- #endif
- }
- #endif
- }
-
- /*
- * find_new_uid - find the next available UID
- *
- * find_new_uid() locates the next highest unused UID in the password
- * file, or checks the given user ID against the existing ones for
- * uniqueness.
- */
-
- int
- find_new_uid ()
- {
- struct passwd *pwd;
-
- /*
- * Start with some UID value if the user didn't provide us with
- * one already.
- */
-
- if (! uflg)
- user_id = 100;
-
- /*
- * Search the entire password file, either looking for this
- * UID (if the user specified one with -u) or looking for the
- * largest unused value.
- */
-
- for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
- if (strcmp (user_name, pwd->pw_name) == 0) {
- fprintf (stderr, "%s: name %s is not unique\n",
- Prog, user_name);
- exit (1);
- }
- if (uflg && user_id == pwd->pw_uid) {
- fprintf (stderr, "%s: uid %d is not unique\n",
- Prog, user_id);
- exit (1);
- }
- if (! uflg && pwd->pw_uid >= user_id)
- user_id = pwd->pw_uid + 1;
- }
- }
-
- /*
- * process_flags - perform command line argument setting
- *
- * process_flags() interprets the command line arguments and sets
- * the values that the user will be created with accordingly. The
- * values are checked for sanity.
- */
-
- void
- process_flags (argc, argv)
- int argc;
- char **argv;
- {
- extern int optind;
- extern char *optarg;
- struct group *grp;
- int anyflag = 0;
- int arg;
-
- while ((arg = getopt (argc, argv, "Du:og:G:d:s:c:mk:f:e:b:")) != EOF) {
- switch (arg) {
- case 'b':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- bflg++;
- if (! Dflg)
- usage ();
-
- strncpy (def_home, optarg, BUFSIZ);
- break;
- case 'c':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- cflg++;
- strncpy (user_comment, optarg, BUFSIZ);
- break;
- case 'd':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- dflg++;
- strncpy (user_home, optarg, BUFSIZ);
- break;
- case 'D':
- if (anyflag)
- usage ();
-
- Dflg++;
- break;
- case 'e':
- eflg++;
- if (Dflg)
- def_expire = atoi (optarg);
- else {
- user_expire = strtoday (optarg);
- #ifdef ITI_AGING
- user_expire *= DAY;
- #endif
- }
- break;
- case 'f':
- fflg++;
- def_inactive = atoi (optarg);
- break;
- case 'g':
- gflg++;
- if (isdigit (optarg[0]))
- grp = getgrgid (atoi (optarg));
- else
- grp = getgrnam (optarg);
-
- if (! grp) {
- fprintf (stderr,
- "%s: unknown group %s\n",
- Prog, optarg);
- exit (1);
- }
- if (Dflg)
- def_group = grp->gr_gid;
- else
- user_gid = grp->gr_gid;
- break;
- case 'G':
- Gflg++;
- if (get_groups (optarg))
- exit (1);
-
- break;
- case 'k':
- if (! mflg)
- usage ();
-
- strncpy (def_template, optarg, BUFSIZ);
- kflg++;
- break;
- case 'm':
- mflg++;
- break;
- case 'o':
- if (! uflg)
- usage ();
-
- oflg++;
- break;
- case 's':
- if (! VALID (optarg)) {
- fprintf (stderr,
- "%s: invalid field `%s'\n",
- Prog, optarg);
- exit (3);
- }
- sflg++;
- strncpy (user_shell, optarg, BUFSIZ);
- break;
- case 'u':
- uflg++;
- user_id = atoi (optarg);
- break;
- default:
- usage ();
- }
- anyflag++;
- }
- if (! Dflg && optind == argc - 1)
- strcpy (user_name, argv[argc - 1]);
-
- if (! dflg)
- sprintf (user_home, "%s/%s", def_home, user_name);
-
- if (! gflg)
- user_gid = def_group;
-
- if (Dflg) {
- if (optind != argc)
- usage ();
-
- if (uflg || oflg || Gflg || dflg ||
- sflg || cflg || mflg || kflg)
- usage ();
- } else {
- if (optind != argc - 1)
- usage ();
- }
- }
-
- /*
- * close_files - close all of the files that were opened
- *
- * close_files() closes all of the files that were opened for this
- * new user. This causes any modified entries to be written out.
- */
-
- close_files ()
- {
- if (! pw_close ()) {
- fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
- exit (1);
- }
- if (! spw_close ()) {
- fprintf (stderr, "%s: cannot rewrite shadow password file\n",
- Prog);
- exit (1);
- }
- if (user_ngroups > 0) {
- if (! gr_close ()) {
- fprintf (stderr, "%s: cannot rewrite group file\n",
- Prog);
- exit (1);
- }
- (void) gr_unlock ();
- #ifdef SHADOWGRP
- if (! sgr_close ()) {
- fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- Prog);
- exit (1);
- }
- (void) sgr_unlock ();
- #endif
- }
- (void) spw_unlock ();
- (void) pw_unlock ();
- }
-
- /*
- * open_files - lock and open the password files
- *
- * open_files() opens the two password files.
- */
-
- open_files ()
- {
- if (! pw_lock ()) {
- fprintf (stderr, "%s: unable to lock password file\n", Prog);
- exit (1);
- }
- if (! pw_open (O_RDWR)) {
- fprintf (stderr, "%s: unable to open password file\n", Prog);
- exit (1);
- }
- if (! spw_lock ()) {
- fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
- exit (1);
- }
- if (! spw_open (O_RDWR)) {
- fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
- exit (1);
- }
- }
-
- /*
- * usr_update - create the user entries
- *
- * usr_update() creates the password file entries for this user
- * and will update the group entries if required.
- */
-
- usr_update ()
- {
- struct passwd pwent;
- struct spwd spent;
-
- if (! oflg)
- find_new_uid ();
-
- new_pwent (&pwent);
- if (! pw_update (&pwent)) {
- fprintf (stderr, "%s: error adding new password entry\n", Prog);
- exit (1);
- }
- new_spent (&spent);
- if (! spw_update (&spent)) {
- fprintf (stderr, "%s: error adding new shadow password entry\n",
- Prog);
- exit (1);
- }
- #if defined(DBM) || defined(NDBM)
- if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (&pwent)) {
- fprintf (stderr, "%s: error updating password dbm entry\n",
- Prog);
- exit (1);
- }
- endpwent ();
- #endif
- #ifdef NDBM
- if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (&spent)) {
- fprintf (stderr, "%s: error updating shadow passwd dbm entry\n",
- Prog);
- exit (1);
- }
- endspent ();
- #endif
- #ifdef USE_SYSLOG
- syslog (LOG_INFO,
- "new user: name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",
- user_name, user_id, user_gid, user_home, user_shell);
- #endif
- if (user_ngroups > 0)
- grp_update ();
- }
-
- /*
- * create_home - create the user's home directory
- *
- * create_home() creates the user's home directory if it does not
- * already exist. It will be created mode 755 owned by the user
- * with the user's default group.
- */
-
- create_home ()
- {
- if (access (user_home, 0)) {
- if (mkdir (user_home, 0755)) {
- fprintf (stderr, "%s: cannot create directory %s\n",
- Prog, user_home);
- exit (1);
- }
- chown (user_home, user_id, user_gid);
- chmod (user_home, 0755);
- }
- }
-
- /*
- * main - useradd command
- */
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- /*
- * Get my name so that I can use it to report errors.
- */
-
- if (Prog = strrchr (argv[0], '/'))
- Prog++;
- else
- Prog = argv[0];
-
- #ifdef USE_SYSLOG
- openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- #endif
-
- /*
- * The open routines for the NDBM files don't use read-write
- * as the mode, so we have to clue them in.
- */
-
- #ifdef NDBM
- pw_dbm_mode = O_RDWR;
- sp_dbm_mode = O_RDWR;
- gr_dbm_mode = O_RDWR;
- #ifdef SHADOWGRP
- sg_dbm_mode = O_RDWR;
- #endif
- #endif
- get_defaults ();
-
- process_flags (argc, argv);
-
- /*
- * See if we are messing with the defaults file, or creating
- * a new user.
- */
-
- if (Dflg) {
- if (gflg || bflg || fflg || eflg)
- exit (set_defaults () ? 1:0);
-
- show_defaults ();
- exit (0);
- }
-
- /*
- * Start with a quick check to see if the user exists.
- */
-
- if (getpwnam (user_name)) {
- fprintf (stderr, "%s: user %s exists\n", Prog, user_name);
- exit (1);
- }
-
- /*
- * Do the hard stuff - open the files, create the user entries,
- * create the home directory, then close and update the files.
- */
-
- open_files ();
-
- usr_update ();
-
- if (mflg) {
- create_home ();
- copy_tree (def_template, user_home, user_id, user_gid);
- }
- close_files ();
- exit (0);
- /*NOTREACHED*/
- }
-